<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 5.2.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"llmysnow.top","root":"/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":true,"show_result":true,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":true},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":true,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="介绍 V8 引擎的垃圾回收机制：分代回收、空间复制、标记清除、标记整理、增量标记；使用 Performance 工具如何去监控内存；结合 JSBench 去优化代码">
<meta property="og:type" content="article">
<meta property="og:title" content="JS 垃圾回收与性能优化">
<meta property="og:url" content="http://llmysnow.top/posts/3344fd09/index.html">
<meta property="og:site_name" content="奇幻的梦之旅">
<meta property="og:description" content="介绍 V8 引擎的垃圾回收机制：分代回收、空间复制、标记清除、标记整理、增量标记；使用 Performance 工具如何去监控内存；结合 JSBench 去优化代码">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E4%B8%80%E6%AE%B5%E4%BB%A3%E7%A0%81%E7%9A%84%E6%80%A7%E8%83%BD.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E5%8F%AF%E8%BE%BE%E5%AF%B9%E8%B1%A1%E5%9B%BE%E7%A4%BA.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E5%8F%AF%E8%BE%BE%E5%AF%B9%E8%B1%A1%E8%BF%9B%E8%A1%8Cdelete.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/GC%E9%87%8C%E7%9A%84%E5%9E%83%E5%9C%BE%E6%98%AF%E4%BB%80%E4%B9%88.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E6%A0%87%E8%AE%B0%E6%B8%85%E9%99%A4.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E6%A0%87%E8%AE%B0%E6%B8%85%E9%99%A4%E7%AE%97%E6%B3%95%E7%BC%BA%E7%82%B9%E5%9B%BE%E8%A7%A3.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E6%95%B4%E7%90%86%E6%B8%85%E9%99%A4%E5%9B%9E%E6%94%B6%E5%89%8D.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E6%95%B4%E7%90%86%E6%B8%85%E9%99%A4%E6%95%B4%E7%90%86%E5%90%8E.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E6%95%B4%E7%90%86%E6%B8%85%E9%99%A4%E5%9B%9E%E6%94%B6%E5%90%8E.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/V8%E5%86%85%E5%AD%98%E7%AD%96%E7%95%A5.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/V8%E6%96%B0%E8%80%81%E7%94%9F%E4%BB%A3%E5%AD%98%E5%82%A8.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E6%A0%87%E8%AE%B0%E5%A2%9E%E9%87%8F.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E6%B5%8F%E8%A7%88%E5%99%A8%E4%BB%BB%E5%8A%A1%E7%AE%A1%E7%90%86%E5%99%A8.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/Timeline%E8%AE%B0%E5%BD%95%E5%86%85%E5%AD%98.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/V8%E5%BC%95%E6%93%8E.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E5%A0%86%E6%A0%88%E6%9C%BA%E5%88%B6.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E5%AF%B9%E8%B1%A1%E5%A0%86%E6%A0%88%E6%89%A7%E8%A1%8C%E6%9C%BA%E5%88%B6.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E4%BC%98%E5%8C%96%E5%87%8F%E5%B0%91%E5%88%A4%E6%96%AD%E5%B1%82%E7%BA%A7.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E4%BC%98%E5%8C%96%E6%85%8E%E7%94%A8%E5%85%A8%E5%B1%80%E5%8F%98%E9%87%8F.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E4%BC%98%E5%8C%96%E7%BC%93%E5%AD%98%E6%95%B0%E6%8D%AE.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E4%BC%98%E5%8C%96%E5%87%8F%E5%B0%91%E8%AE%BF%E9%97%AE%E5%B1%82%E7%BA%A7.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E4%BC%98%E5%8C%96%E5%AD%97%E9%9D%A2%E9%87%8F%E4%B8%8E%E6%9E%84%E9%80%A0%E5%BC%8F.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E4%BC%98%E5%8C%96%E5%87%8F%E5%B0%91%E5%BE%AA%E7%8E%AF%E4%BD%93%E6%B4%BB%E5%8A%A8.png">
<meta property="article:published_time" content="2020-11-29T13:50:15.550Z">
<meta property="article:modified_time" content="2022-04-23T11:27:04.394Z">
<meta property="article:author" content="LiLyn">
<meta property="article:tag" content="JavaScript">
<meta property="article:tag" content="垃圾回收">
<meta property="article:tag" content="性能优化">
<meta property="article:tag" content="Performance">
<meta property="article:tag" content="代码优化">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E4%B8%80%E6%AE%B5%E4%BB%A3%E7%A0%81%E7%9A%84%E6%80%A7%E8%83%BD.png">

<link rel="canonical" href="http://llmysnow.top/posts/3344fd09/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>JS 垃圾回收与性能优化 | 奇幻的梦之旅</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

<link rel="alternate" href="/atom.xml" title="奇幻的梦之旅" type="application/atom+xml">
</head>
<!--即时预加载技术，在用户点击之前预先加载页面-->
<script src="https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.0.2/js/instantclick-1.2.2.js" type="module"></script>
<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>
	  <!--<a target="_blank" rel="noopener" href="https://github.com/llwodexue" class="github-corner" aria-label="View source on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#151513; color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>-->
    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">奇幻的梦之旅</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">http://llmysnow.top/</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div id="search-result">
  <div id="no-result">
    <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
  </div>
</div>

    </div>
  </div>

</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://llmysnow.top/posts/3344fd09/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/logo.jpg">
      <meta itemprop="name" content="LiLyn">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="奇幻的梦之旅">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          JS 垃圾回收与性能优化
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2020-11-29 21:50:15" itemprop="dateCreated datePublished" datetime="2020-11-29T21:50:15+08:00">2020-11-29</time>
            </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/JavaScript/" itemprop="url" rel="index"><span itemprop="name">JavaScript</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>15k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>13 分钟</span>
            </span>
            <div class="post-description">介绍 V8 引擎的垃圾回收机制：分代回收、空间复制、标记清除、标记整理、增量标记；使用 Performance 工具如何去监控内存；结合 JSBench 去优化代码</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <h2 id="JavaScript-内存管理"><a href="#JavaScript-内存管理" class="headerlink" title="JavaScript 内存管理"></a>JavaScript 内存管理</h2><p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E4%B8%80%E6%AE%B5%E4%BB%A3%E7%A0%81%E7%9A%84%E6%80%A7%E8%83%BD.png" alt="一段代码的性能"></p>
<p><strong>内存管理</strong></p>
<ul>
<li>内存：由可读写单元组成，表示一片可操作性空间</li>
<li>管理：人为的去操作一片空间的申请、使用和释放</li>
<li>内存管理：开发者主动申请空间、使用空间、释放空间</li>
<li>管理流程：申请-使用-释放</li>
</ul>
<p><strong>JS 内存管理</strong></p>
<ul>
<li>申请内存空间</li>
<li>使用内存空间</li>
<li>释放内存空间</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 申请空间</span></span><br><span class="line"><span class="keyword">let</span> obj = &#123;&#125;</span><br><span class="line"><span class="comment">// 使用空间</span></span><br><span class="line">obj.name = <span class="string">&#x27;jack&#x27;</span></span><br><span class="line"><span class="comment">// 释放空间</span></span><br><span class="line">obj = <span class="literal">null</span></span><br></pre></td></tr></table></figure>

<h2 id="垃圾回收与常见-GC-算法"><a href="#垃圾回收与常见-GC-算法" class="headerlink" title="垃圾回收与常见 GC 算法"></a>垃圾回收与常见 GC 算法</h2><h3 id="JavaScript-中的垃圾回收"><a href="#JavaScript-中的垃圾回收" class="headerlink" title="JavaScript 中的垃圾回收"></a>JavaScript 中的垃圾回收</h3><ul>
<li>JavaScript 中内存管理是自动的</li>
<li>对象不再被 <strong>引用</strong> 时是垃圾</li>
<li>对象不能 <strong>从根上访问到</strong> 时是垃圾</li>
</ul>
<p><strong>JavaScript 中的可达对象</strong></p>
<ul>
<li>可以访问到的对象就是可达对象（引用、作用域链）</li>
<li>可达的标准就是从根出发是否能够被找到</li>
<li>JavaScript 中的根可以理解为 <strong>全局变量</strong></li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> obj = &#123; <span class="attr">name</span>: <span class="string">&#x27;bird&#x27;</span> &#125;</span><br><span class="line"><span class="keyword">let</span> dog = obj</span><br><span class="line"><span class="comment">// 虽然被清理了，但是dog还在引用着，还是可达的</span></span><br><span class="line">obj = <span class="literal">null</span></span><br></pre></td></tr></table></figure>

<p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E5%8F%AF%E8%BE%BE%E5%AF%B9%E8%B1%A1%E5%9B%BE%E7%A4%BA.png" alt="可达对象图示"></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">objGroup</span>(<span class="params">obj1, obj2</span>) </span>&#123;</span><br><span class="line">  obj1.next = obj2</span><br><span class="line">  obj2.prev = obj1</span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line">    o1: obj1,</span><br><span class="line">    o2: obj2,</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> obj = objGroup(&#123; <span class="attr">name</span>: <span class="string">&#x27;obj1&#x27;</span> &#125;, &#123; <span class="attr">name</span>: <span class="string">&#x27;obj2&#x27;</span> &#125;)</span><br></pre></td></tr></table></figure>

<p>现在通过 delete 语句，把 obj 中对 o1 的引用（<code>delete obj.o1</code>）以及 obj2 对 obj1 的引用（<code>delete obj2.prev</code>）都 delete 掉，因为没有办法通过某些方式找到 o1，所以 o1 会被垃圾回收</p>
<p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E5%8F%AF%E8%BE%BE%E5%AF%B9%E8%B1%A1%E8%BF%9B%E8%A1%8Cdelete.png" alt="可达对象进行delete"></p>
<h3 id="GC-算法"><a href="#GC-算法" class="headerlink" title="GC 算法"></a>GC 算法</h3><p><strong>GC 定义与作用</strong></p>
<ul>
<li>GC 就是垃圾回收机制的简写（Garbage Collection）</li>
<li>GC 可以找到内存中的垃圾、并释放和回收空间</li>
</ul>
<p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/GC%E9%87%8C%E7%9A%84%E5%9E%83%E5%9C%BE%E6%98%AF%E4%BB%80%E4%B9%88.png" alt="GC里的垃圾是什么"></p>
<p><strong>GC 算法是什么</strong></p>
<ul>
<li>GC 是一种机制，垃圾回收器完成具体的工作</li>
<li>工作的内容就是查找垃圾释放空间、回收空间</li>
<li>算法就是工作时查找和回收所遵循的规则</li>
</ul>
<p><strong>常见 GC 算法</strong></p>
<ul>
<li>引用计数</li>
<li>标记清除</li>
<li>标记整理</li>
<li>分代回收</li>
</ul>
<h4 id="引用计数"><a href="#引用计数" class="headerlink" title="引用计数"></a>引用计数</h4><ul>
<li>核心思想：设置引用数，判断当前引用数是否为 0</li>
<li>引用计数器，引用关系改变时修改引用数字</li>
<li>引用数字为 0 时立即回收</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> user1 = &#123; <span class="attr">age</span>: <span class="number">11</span> &#125;</span><br><span class="line"><span class="keyword">const</span> user2 = &#123; <span class="attr">age</span>: <span class="number">22</span> &#125;</span><br><span class="line"><span class="comment">// 即使脚本执行完，因为在全局还是找到到，所以不会被回收</span></span><br><span class="line"><span class="keyword">const</span> nameList = [user1.age, user2.age]</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fn</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="comment">// 因为挂载在window上，即使fn执行完毕，计数也不是0</span></span><br><span class="line">  num1 = <span class="number">1</span></span><br><span class="line">  <span class="comment">// 加上const后只在作用域内起作用，从全局是找不到的，计数为0</span></span><br><span class="line">  <span class="keyword">const</span> num2 = <span class="number">2</span></span><br><span class="line">&#125;</span><br><span class="line">fn()</span><br></pre></td></tr></table></figure>

<p><strong>引用计数算法优缺点</strong></p>
<ul>
<li><p>优点：发现垃圾时立即回收；最大限度减少程序卡顿时间</p>
</li>
<li><p>缺点：无法回收循环引用的对象；资源消耗较大、时间开销较大（需要监控对象数值变化）</p>
</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fn</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> obj1 = &#123;&#125;</span><br><span class="line">  <span class="keyword">const</span> obj2 = &#123;&#125;</span><br><span class="line">	<span class="comment">// obj1引用obj2，obj2引用obj1</span></span><br><span class="line">  obj1.name = obj2</span><br><span class="line">  obj2.name = obj1</span><br><span class="line">&#125;</span><br><span class="line">fn()</span><br></pre></td></tr></table></figure>

<h4 id="标记清除"><a href="#标记清除" class="headerlink" title="标记清除"></a>标记清除</h4><ul>
<li>核心思想：分标记和清除两个阶段完成</li>
<li>遍历所有对象找到标记活动对象</li>
<li>遍历所有对象清除没有标记对象</li>
<li>回收相应的空间</li>
</ul>
<p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E6%A0%87%E8%AE%B0%E6%B8%85%E9%99%A4.png" alt="标记清除"></p>
<p><strong>标记清除算法优缺点</strong></p>
<ul>
<li><p>优点：相对引用计数来说，解决了对象循环引用无法回收问题</p>
</li>
<li><p>缺点：容易产生空间碎片化、浪费空间（当前回收的对象在地址上是不连续的）；不会立即回收垃圾对象</p>
<p>任何空间都会有两部分组成，一个是存储空间的头元信息（大小、地址），另一个是存放数据的域</p>
</li>
</ul>
<p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E6%A0%87%E8%AE%B0%E6%B8%85%E9%99%A4%E7%AE%97%E6%B3%95%E7%BC%BA%E7%82%B9%E5%9B%BE%E8%A7%A3.png" alt="标记清除算法缺点图解"></p>
<h4 id="标记整理"><a href="#标记整理" class="headerlink" title="标记整理"></a>标记整理</h4><ul>
<li>标记整理可以看做是标记清除的增强</li>
<li>标记阶段的操作和标记清除一致</li>
<li>清除阶段会先执行整理，移动对象位置</li>
</ul>
<p>有很多活动对象、非活动对象、空闲空间</p>
<p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E6%95%B4%E7%90%86%E6%B8%85%E9%99%A4%E5%9B%9E%E6%94%B6%E5%89%8D.png" alt="整理清除回收前"></p>
<p>执行标记整理，会将活动对象进行整理，地址变为连续</p>
<p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E6%95%B4%E7%90%86%E6%B8%85%E9%99%A4%E6%95%B4%E7%90%86%E5%90%8E.png" alt="整理清除整理后"></p>
<p>这样回收后就可以最大化利用空间</p>
<p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E6%95%B4%E7%90%86%E6%B8%85%E9%99%A4%E5%9B%9E%E6%94%B6%E5%90%8E.png" alt="整理清除回收后"></p>
<p><strong>标记清除算法优缺点</strong></p>
<ul>
<li>优点：减少碎片化空间</li>
<li>缺点：不会立即回收垃圾对象</li>
</ul>
<h2 id="V8-引擎的垃圾回收"><a href="#V8-引擎的垃圾回收" class="headerlink" title="V8 引擎的垃圾回收"></a>V8 引擎的垃圾回收</h2><ul>
<li><p>V8 是一款主流 JavaScript 执行引擎</p>
</li>
<li><p>V8 采用即时编译</p>
<p>之前很多 JavaScript 引擎都需要将代码先转换成字节码，然后去执行。V8 可以直接将源码翻译成可执行的机器码，所以速度非常快</p>
</li>
<li><p>V8 内存设限</p>
<p>64位不超过 1.5G，32位不超过 800M</p>
<p>当垃圾回收达到 1.5G 时，采用增量标记进行垃圾回收，只需消耗 50ms，如果采用非增量标记去进行垃圾回收，需要 1s</p>
</li>
<li><p>V8 采用基于分代回收思想实现垃圾回收</p>
<p>V8 内存分为新生代（复制 + 标记整理）和老生代（标记清除 + 标记整理 + 增量标记）</p>
</li>
</ul>
<h3 id="V8-垃圾回收策略"><a href="#V8-垃圾回收策略" class="headerlink" title="V8 垃圾回收策略"></a>V8 垃圾回收策略</h3><ul>
<li>采用分代回收的思想</li>
<li>内存分为新生代、老生代</li>
<li>针对不同对象采用不同算法</li>
</ul>
<p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/V8%E5%86%85%E5%AD%98%E7%AD%96%E7%95%A5.png" alt="V8内存策略"></p>
<p><strong>V8 中常用 GC 算法</strong></p>
<ul>
<li>分代回收</li>
<li>空间复制</li>
<li>标记清除</li>
<li>标记整理</li>
<li>增量标记</li>
</ul>
<h3 id="V8-回收新老生代对象"><a href="#V8-回收新老生代对象" class="headerlink" title="V8 回收新老生代对象"></a>V8 回收新老生代对象</h3><p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/V8%E6%96%B0%E8%80%81%E7%94%9F%E4%BB%A3%E5%AD%98%E5%82%A8.png" alt="V8新老生代存储"></p>
<ul>
<li><p><strong>V8 内存空间一分为二</strong>（左侧-&gt;新生代；右侧-&gt;老生代）</p>
</li>
<li><p>左侧小空间用于存储新生代对象（64位32M | 32位16M）</p>
<p>新生代指的是存活时间较短的对象</p>
</li>
<li><p>右侧大空间用于存储老生代对象（64位1.4G | 32位700M）</p>
<p>老生代对象就是指存活时间较长的对象（Global、Closure）</p>
</li>
</ul>
<p><strong>新生代回收实现</strong></p>
<ul>
<li><p>回收过程采用复制算法 + 标记整理</p>
</li>
<li><p><strong>新生代内存区分为两个等大小空间</strong></p>
</li>
<li><p>使用空间为 From，空闲空间为 To</p>
</li>
<li><p>活动对象存储于 From 空间</p>
<p>如果要申请空间来会用，首先会所有变量对象都分配到 From 空间</p>
<p>一旦 From 空间达到一定存储量后，就会触发 GC 操作</p>
</li>
<li><p>标记整理后将活动对象拷贝至 To</p>
<p>这时候位置连续，没有碎片化空间</p>
</li>
<li><p>From 与 To 交换空间完成释放</p>
</li>
</ul>
<p><strong>新生代回收细节说明</strong></p>
<ul>
<li><p>拷贝过程中可能出现晋升（晋升就是将新生代对象移动至老生代）</p>
<p>一轮 GC 还活的新生代需要晋升</p>
<p>To 空间的使用率超过 25%</p>
</li>
</ul>
<p><strong>老生代回收实现</strong></p>
<ul>
<li>主要采用标记清除、标记整理、增量标记算法</li>
<li>首先使用标记清除完成垃圾空间的回收</li>
<li>采用标记整理进行空间优化</li>
<li>采用增量标记进行效率优化</li>
</ul>
<p><strong>细节对比</strong></p>
<ul>
<li>新生代区域垃圾回收使用空间换时间</li>
<li>老生代区域垃圾回收不适合复制算法</li>
</ul>
<p><strong>标记增量如何优化垃圾回收</strong></p>
<ul>
<li>当进行垃圾回收时会阻塞 JavaScript 执行</li>
<li>标记增量就是将一整段垃圾回收操作拆分成多个小步组合完成回收，这样执行程序和垃圾回收交替进行</li>
</ul>
<p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E6%A0%87%E8%AE%B0%E5%A2%9E%E9%87%8F.png" alt="标记增量"></p>
<h2 id="Performance-工具"><a href="#Performance-工具" class="headerlink" title="Performance 工具"></a>Performance 工具</h2><p>GC 的目的是为了实现内存空间的良性循环</p>
<ul>
<li>良性循环的基石是合理使用，时刻关注才能确定是否合理</li>
<li>通过 Performance 时刻监控内存</li>
</ul>
<p><strong>内存问题的外在表现</strong></p>
<ul>
<li><p>页面出现延迟加载或经常性暂停</p>
<p>频繁垃圾回收，某一块代码瞬间让内存爆掉（通过内存变化图进行分析）</p>
</li>
<li><p>页面持续性出现糟糕的性能</p>
<p>内存膨胀，当前界面为了达到最佳使用速度会申请内存空间，但这个内存空间远超当前设备所能提供的大小</p>
</li>
<li><p>页面的性能随时间越长越来越差</p>
<p>出现内存泄露，内存使用持续升高</p>
</li>
</ul>
<p><strong>监控内存的几种方式</strong></p>
<ul>
<li>浏览器任务管理器</li>
<li>TimeLine 时序图记录</li>
<li>堆快照查找分离 DOM</li>
<li>判断是否存在频繁的垃圾回收</li>
</ul>
<p><strong>为什么要确定频繁垃圾回收</strong></p>
<ul>
<li>GC 工作时应用程序是停止的</li>
<li>频繁且过长的 GC 会导致应用假死</li>
<li>用户使用中感知应用卡顿</li>
</ul>
<p><strong>确定频繁的垃圾回收</strong></p>
<ul>
<li>Timeline 中频繁的上升下降</li>
<li>任务管理器中数据频繁的增加减少</li>
</ul>
<h3 id="任务管理器监控内存"><a href="#任务管理器监控内存" class="headerlink" title="任务管理器监控内存"></a>任务管理器监控内存</h3><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="meta-keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">&quot;viewport&quot;</span> <span class="attr">content</span>=<span class="string">&quot;width=device-width, initial-scale=1.0&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>任务管理器监控内存变化<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">button</span> <span class="attr">id</span>=<span class="string">&quot;btn&quot;</span>&gt;</span>Add<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="javascript">      <span class="keyword">const</span> btn = <span class="built_in">document</span>.getElementById(<span class="string">&#x27;btn&#x27;</span>)</span></span><br><span class="line"><span class="javascript">      btn.onclick = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">        <span class="keyword">let</span> arrList = <span class="keyword">new</span> <span class="built_in">Array</span>(<span class="number">1000000</span>)</span></span><br><span class="line">      &#125;</span><br><span class="line">    <span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure>

<ul>
<li><code>Shift + Esc</code> 打开浏览器的任务管理器（右键把 JavaScript 内存勾上）</li>
<li>主要看当前 DOM 所占用的内存变化、JavaScript 堆所占内存变化</li>
</ul>
<p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E6%B5%8F%E8%A7%88%E5%99%A8%E4%BB%BB%E5%8A%A1%E7%AE%A1%E7%90%86%E5%99%A8.png" alt="浏览器任务管理器"></p>
<h3 id="Timeline-记录内存"><a href="#Timeline-记录内存" class="headerlink" title="Timeline 记录内存"></a>Timeline 记录内存</h3><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="meta-keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">&quot;viewport&quot;</span> <span class="attr">content</span>=<span class="string">&quot;width=device-width, initial-scale=1.0&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>时间线记录内存变化<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">button</span> <span class="attr">id</span>=<span class="string">&quot;btn&quot;</span>&gt;</span>Add<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="javascript">      <span class="keyword">const</span> arr = []</span></span><br><span class="line"><span class="javascript">      <span class="function"><span class="keyword">function</span> <span class="title">test</span>(<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">        <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">100000</span>; i++) &#123;</span></span><br><span class="line"><span class="javascript">          <span class="built_in">document</span>.body.appendChild(<span class="built_in">document</span>.createElement(<span class="string">&#x27;p&#x27;</span>))</span></span><br><span class="line">        &#125;</span><br><span class="line"><span class="javascript">        arr.push(<span class="keyword">new</span> <span class="built_in">Array</span>(<span class="number">1000000</span>).join(<span class="string">&#x27;x&#x27;</span>))</span></span><br><span class="line">      &#125;</span><br><span class="line"><span class="javascript">      <span class="built_in">document</span>.getElementById(<span class="string">&#x27;btn&#x27;</span>).addEventListener(<span class="string">&#x27;click&#x27;</span>, test)</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/Timeline%E8%AE%B0%E5%BD%95%E5%86%85%E5%AD%98.png" alt="Timeline记录内存"></p>
<h3 id="堆快照查询分离-DOM"><a href="#堆快照查询分离-DOM" class="headerlink" title="堆快照查询分离 DOM"></a>堆快照查询分离 DOM</h3><ul>
<li><p>页面元素存活在 DOM 树上</p>
</li>
<li><p>垃圾对象时的 DOM 节点</p>
<p>脱离 DOM 树就是垃圾，而且 JS 没有引用这个 DOM </p>
</li>
<li><p>分离状态的 DOM 节点</p>
<p>当前 DOM 节点只是从 DOM 树上脱离了，但是在 JS 代码中还在引用着，这种 DOM 称为分离 DOM</p>
<p>分离 DOM 是看不见的，但是在内存中却占据空间（内存泄露），可以通过堆快照功能把它从这里都找出来</p>
</li>
</ul>
<p><strong>注意：</strong> 如果 <code>console.log</code> 也打印了 ul，那么 ul 也是被引用的，搜索 <code>Detached</code> 也会有分离 DOM</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="meta-keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">&quot;viewport&quot;</span> <span class="attr">content</span>=<span class="string">&quot;width=device-width, initial-scale=1.0&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>堆快照监控内存<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">button</span> <span class="attr">id</span>=<span class="string">&quot;id&quot;</span>&gt;</span>Add<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="javascript">      <span class="keyword">var</span> temEle</span></span><br><span class="line"><span class="javascript">      <span class="keyword">var</span> btn = <span class="built_in">document</span>.getElementById(<span class="string">&#x27;id&#x27;</span>)</span></span><br><span class="line"><span class="javascript">      btn.addEventListener(<span class="string">&#x27;click&#x27;</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">        <span class="keyword">var</span> ul = <span class="built_in">document</span>.createElement(<span class="string">&#x27;ul&#x27;</span>)</span></span><br><span class="line"><span class="javascript">        <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span></span><br><span class="line"><span class="javascript">          <span class="keyword">var</span> li = <span class="built_in">document</span>.createElement(<span class="string">&#x27;li&#x27;</span>)</span></span><br><span class="line">          ul.appendChild(li)</span><br><span class="line">        &#125;</span><br><span class="line"><span class="javascript">        <span class="built_in">console</span>.log(ul) <span class="comment">// console.log也被引用记得注释</span></span></span><br><span class="line">        temEle = ul</span><br><span class="line"><span class="javascript">  			temEle = <span class="literal">null</span></span></span><br><span class="line">      &#125;)</span><br><span class="line">    <span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h2 id="V8-引擎工作流程"><a href="#V8-引擎工作流程" class="headerlink" title="V8 引擎工作流程"></a>V8 引擎工作流程</h2><ul>
<li><p>V8 引擎只是浏览器渲染引擎的 JS 执行代码的组成部分</p>
</li>
<li><p><code>Scanner</code> 是一个扫描器，对于纯文本 JS 代码进行词法分析，把代码分析成不同 tokens</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> username = <span class="string">&#x27;alishi&#x27;</span></span><br><span class="line"></span><br><span class="line">[</span><br><span class="line">  &#123; <span class="attr">type</span>: <span class="string">&#x27;Keyword&#x27;</span>, <span class="attr">value</span>: <span class="string">&#x27;const&#x27;</span> &#125;, <span class="comment">// 关键词</span></span><br><span class="line">  &#123; <span class="attr">type</span>: <span class="string">&#x27;Identifier&#x27;</span>, <span class="attr">value</span>: <span class="string">&#x27;username&#x27;</span> &#125;, <span class="comment">// 标识符</span></span><br><span class="line">  &#123; <span class="attr">type</span>: <span class="string">&#x27;Punctuator&#x27;</span>, <span class="attr">value</span>: <span class="string">&#x27;=&#x27;</span> &#125;, <span class="comment">// 标点符号</span></span><br><span class="line">  &#123; <span class="attr">type</span>: <span class="string">&#x27;String&#x27;</span>, <span class="attr">value</span>: <span class="string">&#x27;alishi&#x27;</span> &#125;,</span><br><span class="line">]</span><br></pre></td></tr></table></figure>
</li>
<li><p><code>Parser</code> 是一个解析器（全量解析），解析的过程就是语法分析过程，把词法分析 tokens 转换成抽象语法树（AST）</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  type: <span class="string">&#x27;Program&#x27;</span>,</span><br><span class="line">  body: [</span><br><span class="line">    &#123;</span><br><span class="line">      type: <span class="string">&#x27;VariableDeclaration&#x27;</span>,</span><br><span class="line">      declaration: [</span><br><span class="line">        &#123;</span><br><span class="line">          type: <span class="string">&#x27;VariableDeclarator&#x27;</span>,</span><br><span class="line">          id: &#123;</span><br><span class="line">            type: <span class="string">&#x27;Identifier&#x27;</span>,</span><br><span class="line">            name: <span class="string">&#x27;username&#x27;</span>,</span><br><span class="line">          &#125;,</span><br><span class="line">          init: &#123;</span><br><span class="line">            type: <span class="string">&#x27;Literal&#x27;</span>,</span><br><span class="line">            value: <span class="string">&#x27;alishi&#x27;</span>,</span><br><span class="line">            raw: <span class="string">&#x27;alishi&#x27;</span>,</span><br><span class="line">          &#125;,</span><br><span class="line">        &#125;,</span><br><span class="line">      ],</span><br><span class="line">      kind: <span class="string">&#x27;const&#x27;</span>,</span><br><span class="line">    &#125;,</span><br><span class="line">  ],</span><br><span class="line">  sourceType: <span class="string">&#x27;script&#x27;</span>,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p><code>PreParser</code> 是预解析，比如：定义一个函数但没有立即对它进行调用，使用全量解析就有很多无用功</p>
</li>
<li><p><code>Ignition</code> 是解释器，把抽象语法树（AST）转换成字节码（bytecode），并收集下一个编译阶段的信息</p>
</li>
<li><p><code>TurboFan</code> 是编译器模块，把字节码转换成汇编代码</p>
</li>
</ul>
<p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/V8%E5%BC%95%E6%93%8E.png" alt="V8引擎"></p>
<p><strong>预解析</strong></p>
<ul>
<li>跳过未被使用的代码</li>
<li>不生成 AST，创建无变量引用和声明的 scopes</li>
<li>依据规范抛出特定错误</li>
<li>解析速度更快</li>
</ul>
<p><strong>全量解析</strong></p>
<ul>
<li>解析被使用的代码</li>
<li>生成 AST</li>
<li>构建具体 scopes 信息，变量引用、声明等</li>
<li>抛出所有语法错误</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 声明时未调用，因此会被认为是不被执行的代码，进行预解析</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&#x27;foo&#x27;</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 声明时未调用，因此会被认为是不被执行的代码，进行预解析</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fn</span>(<span class="params"></span>) </span>&#123;&#125;</span><br><span class="line"><span class="comment">// 函数立即执行，只进行一次全量解析</span></span><br><span class="line">;(<span class="function"><span class="keyword">function</span> <span class="title">bar</span>(<span class="params"></span>) </span>&#123;&#125;)()</span><br><span class="line"><span class="comment">// 执行 foo，那么需要重新对 foo 函数进行全量解析，此时 foo 函数被解析了两次</span></span><br></pre></td></tr></table></figure>

<h2 id="堆栈内存处理"><a href="#堆栈内存处理" class="headerlink" title="堆栈内存处理"></a>堆栈内存处理</h2><ul>
<li><p><strong>执行环境栈（ECStack，Execution Context Stack）</strong></p>
<p>浏览器想要执行代码，首先需要从内存中分配出一块内存，用来执行代码（栈内存）</p>
</li>
<li><p>执行上下文</p>
<p>不能将所有代码都放在执行环境栈，需要执行上下文管理在不同区域</p>
<p>包括：<strong>全局执行上下文（EC(G)，Execution Context Global）</strong>、函数上下文、块级上下文</p>
</li>
<li><p><strong>全局对象（GO，Global Object）</strong> 堆</p>
<p>存储浏览器内部的 API（<code>window.setTimeout...</code>），也是一个对象，它会有一个内存地址，有地址就可以对其进行访问</p>
</li>
<li><p><strong>全局变量对象（VO(G)，Variable Object Global）</strong> 栈</p>
<p>存储当前上下文中生成的变量（块级上下文也是 VO）</p>
<p>为了方便我们使用 GO 对象里面的属性（<code>setTimeout</code>），所以 VO(G) 里有 window 变量</p>
</li>
<li><p>活动对象（AO，Active Object）</p>
<p>存储函数中的变量对象（私有），可以理解为是 VO 的分支</p>
</li>
</ul>
<h3 id="基本数据类型"><a href="#基本数据类型" class="headerlink" title="基本数据类型"></a>基本数据类型</h3><p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E5%A0%86%E6%A0%88%E6%9C%BA%E5%88%B6.png" alt="堆栈机制"></p>
<ol>
<li>基本数据类型是按值进行操作</li>
<li>基本数据类型是存放在栈区的</li>
<li>无论我们当前看到的栈内存，还是后续引用数据类型会使用的堆内存都属于计算机内存</li>
<li>GO 它不是 VO(G)，但是它也是一个对象，因此它会有一个内存的空间地址</li>
</ol>
<h3 id="引用数据类型"><a href="#引用数据类型" class="headerlink" title="引用数据类型"></a>引用数据类型</h3><p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E5%AF%B9%E8%B1%A1%E5%A0%86%E6%A0%88%E6%89%A7%E8%A1%8C%E6%9C%BA%E5%88%B6.png" alt="对象堆栈执行机制"></p>
<h3 id="函数堆栈处理"><a href="#函数堆栈处理" class="headerlink" title="函数堆栈处理"></a>函数堆栈处理</h3><ol>
<li><p>创建函数和创建变量类似，函数名此时就可以看做是一个变量名</p>
</li>
<li><p>单独开辟一个堆内存用于存放函数的体（字符串形式代码）</p>
<p>当前内存地址也会有一个 16 进制数值地址</p>
</li>
<li><p>创建函数的时候，它的作用域 <code>[[scope]]</code> 就已经确定了（创建函数时所在的执行上下文）</p>
</li>
<li><p>创建函数之后会将它的内存地址存放在栈区与对应的函数名进行关联</p>
</li>
</ol>
<p>函数执行，目的就是为了将函数数据对应的堆内存里的字符串形式代码进行执行，代码在执行时肯定需要有一个环境，此时就意味着函数在执行的时候会生成一个新的执行上下文来管理函数体中的代码</p>
<p><strong>函数执行时做的事情</strong></p>
<ol>
<li>确定作用域链 <code>&lt;当前执行上下文, 上级执行上下文&gt;</code></li>
<li>确定 this</li>
<li>初始化 arguments 对象</li>
<li>形参赋值：相当于变量声明，然后将声明变化放置于 AO</li>
<li>变量提升</li>
<li>执行代码</li>
</ol>
<h3 id="闭包堆栈处理"><a href="#闭包堆栈处理" class="headerlink" title="闭包堆栈处理"></a>闭包堆栈处理</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> a = <span class="number">1</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> b = <span class="number">2</span></span><br><span class="line">  <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> (<span class="params">c</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(c + b++)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> f = foo()</span><br><span class="line">f(<span class="number">5</span>) <span class="comment">// 7 b-&gt;3</span></span><br><span class="line">f(<span class="number">10</span>) <span class="comment">// 13 b-&gt;4</span></span><br></pre></td></tr></table></figure>

<ol>
<li><p>闭包是一种机制，通过私有上下文来保护当中变量的机制</p>
</li>
<li><p>我们也可以认为当我们创建的某一个执行上下文不被释放的时候就形成了闭包（临时不被释放）</p>
<p>保护：当前上下文中的变量与其它上下文中的变量互不干扰</p>
<p>保存：当前上下文的数据（堆内存）被当前上下文以外的上下文中的变量所引用，这个数据就保存下来了</p>
</li>
</ol>
<h2 id="代码优化"><a href="#代码优化" class="headerlink" title="代码优化"></a>代码优化</h2><h3 id="闭包与垃圾回收"><a href="#闭包与垃圾回收" class="headerlink" title="闭包与垃圾回收"></a>闭包与垃圾回收</h3><ol>
<li>浏览器都自有垃圾回收（内存管理，V8 为例）</li>
<li>栈空间、堆空间</li>
<li>堆：当前堆内存如果被占用，就不能被释放掉，但是我们如果确认后续不再使用这个内存的数据，也可以自己主动置空，然后浏览器会对其进行回收</li>
<li>栈：当前上下文中是否有内容，被其上下文的变量所占用，如果有则无法释放（闭包）</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> a = <span class="number">10</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params">a</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> (<span class="params">b</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(b + ++a)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> fn = foo(<span class="number">10</span>)</span><br><span class="line">fn(<span class="number">5</span>) <span class="comment">// 16 私有a-&gt;11</span></span><br><span class="line">foo(<span class="number">6</span>)(<span class="number">7</span>) <span class="comment">// 14</span></span><br><span class="line">fn(<span class="number">20</span>) <span class="comment">// 32 私有a-&gt;12</span></span><br><span class="line"><span class="built_in">console</span>.log(a) <span class="comment">// 10</span></span><br><span class="line"></span><br><span class="line">fn = <span class="literal">null</span></span><br><span class="line">foo = <span class="literal">null</span></span><br></pre></td></tr></table></figure>

<h3 id="循环添加事件"><a href="#循环添加事件" class="headerlink" title="循环添加事件"></a>循环添加事件</h3><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">button</span>&gt;</span>按钮1<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span>&gt;</span>按钮2<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span>&gt;</span>按钮3<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="javascript">  <span class="keyword">var</span> aButtons = <span class="built_in">document</span>.querySelectorAll(<span class="string">&#x27;button&#x27;</span>)</span></span><br><span class="line"><span class="javascript">  <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; aButtons.length; i++) &#123;</span></span><br><span class="line"><span class="javascript">    aButtons[i].onclick = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">      <span class="built_in">console</span>.log(<span class="string">`当前索引值为<span class="subst">$&#123;i&#125;</span>`</span>)</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line"><span class="javascript">  <span class="comment">// 闭包</span></span></span><br><span class="line"><span class="javascript">  <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; aButtons.length; i++) &#123;</span></span><br><span class="line"><span class="javascript">    aButtons[i].onclick = (<span class="function"><span class="keyword">function</span> (<span class="params">i</span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">      <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">        <span class="built_in">console</span>.log(<span class="string">`当前索引值为<span class="subst">$&#123;i&#125;</span>`</span>)</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)(i)</span><br><span class="line">  &#125;</span><br><span class="line"><span class="javascript">  <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; aButtons.length; i++) &#123;</span></span><br><span class="line"><span class="javascript">    aButtons[i].onclick = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">      <span class="built_in">console</span>.log(<span class="string">`当前索引值为<span class="subst">$&#123;i&#125;</span>`</span>)</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"><span class="javascript">  <span class="comment">// 添加自定义属性</span></span></span><br><span class="line"><span class="javascript">  <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; aButtons.length; i++) &#123;</span></span><br><span class="line">    aButtons[i].myIndex = i</span><br><span class="line"><span class="javascript">    aButtons[i].onclick = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">      <span class="built_in">console</span>.log(<span class="string">`当前索引值为<span class="subst">$&#123;<span class="built_in">this</span>.myIndex&#125;</span>`</span>)</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h3 id="事件委托"><a href="#事件委托" class="headerlink" title="事件委托"></a>事件委托</h3><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">index</span>=<span class="string">&quot;1&quot;</span>&gt;</span>按钮1<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">index</span>=<span class="string">&quot;2&quot;</span>&gt;</span>按钮2<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">index</span>=<span class="string">&quot;3&quot;</span>&gt;</span>按钮3<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="javascript">  <span class="built_in">document</span>.body.onclick = <span class="function"><span class="keyword">function</span> (<span class="params">ev</span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">    <span class="keyword">var</span> target = ev.target,</span></span><br><span class="line">      targetDom = target.tagName</span><br><span class="line"><span class="javascript">    <span class="keyword">if</span> (targetDom === <span class="string">&#x27;BUTTON&#x27;</span>) &#123;</span></span><br><span class="line"><span class="javascript">      <span class="keyword">var</span> index = target.getAttribute(<span class="string">&#x27;index&#x27;</span>)</span></span><br><span class="line"><span class="javascript">      <span class="built_in">console</span>.log(<span class="string">`当前点击的是第 <span class="subst">$&#123;index&#125;</span> 个`</span>)</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h2 id="JSBench"><a href="#JSBench" class="headerlink" title="JSBench"></a>JSBench</h2><blockquote>
<p><a target="_blank" rel="noopener" href="https://jsbench.me/">https://jsbench.me/</a></p>
<p><a target="_blank" rel="noopener" href="https://jsperf.com/">https://jsperf.com/</a></p>
</blockquote>
<p>高性能的背后是数据快速存取，也是优秀内存管理的体现</p>
<ul>
<li><code>Setup HTML</code>：初始化 HTML 元素</li>
<li><code>Setup JS</code>：初始化 JS 代码</li>
<li><code>Teardown JS</code>：一些收尾的统一操作</li>
</ul>
<h3 id="减少判断层级"><a href="#减少判断层级" class="headerlink" title="减少判断层级"></a>减少判断层级</h3><ul>
<li><p>对于判断条件嵌套的场景，可以提前 return 那些无效条件</p>
</li>
<li><p>如果条件判断是明确条件的枚举值，一般使用 <code>switch...case</code> 来做，代码更加清晰、易于维护</p>
<p><code>if...else</code> 主要是区间判断</p>
</li>
</ul>
<p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E4%BC%98%E5%8C%96%E5%87%8F%E5%B0%91%E5%88%A4%E6%96%AD%E5%B1%82%E7%BA%A7.png" alt="优化减少判断层级"></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">doSomething</span>(<span class="params">part, chapter</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> parts = [<span class="string">&#x27;ES2015&#x27;</span>, <span class="string">&#x27;ES2016&#x27;</span>, <span class="string">&#x27;工程化&#x27;</span>, <span class="string">&#x27;Vue&#x27;</span>, <span class="string">&#x27;React&#x27;</span>, <span class="string">&#x27;Node&#x27;</span>]</span><br><span class="line">  <span class="keyword">if</span> (part) &#123;</span><br><span class="line">    <span class="keyword">if</span> (parts.includes(part)) &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">&#x27;属于当前的前端课程&#x27;</span>)</span><br><span class="line">      <span class="keyword">if</span> (chapter &gt; <span class="number">5</span>) &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">&#x27;您需要提供 VIP 身份&#x27;</span>)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">&#x27;请确认模块信息&#x27;</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 提前 return</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">doSomething</span>(<span class="params">part, chapter</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> parts = [<span class="string">&#x27;ES2015&#x27;</span>, <span class="string">&#x27;ES2016&#x27;</span>, <span class="string">&#x27;工程化&#x27;</span>, <span class="string">&#x27;Vue&#x27;</span>, <span class="string">&#x27;React&#x27;</span>, <span class="string">&#x27;Node&#x27;</span>]</span><br><span class="line">  <span class="keyword">if</span> (!part) &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">&#x27;请确认模块信息&#x27;</span>)</span><br><span class="line">    <span class="keyword">return</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (!parts.includes(part)) <span class="keyword">return</span></span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">&#x27;属于当前的前端课程&#x27;</span>)</span><br><span class="line">  <span class="keyword">if</span> (chapter &gt; <span class="number">5</span>) &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">&#x27;您需要提供 VIP 身份&#x27;</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">doSomething2(<span class="string">&#x27;ES2016&#x27;</span>, <span class="number">6</span>)</span><br></pre></td></tr></table></figure>

<h3 id="慎用全局变量"><a href="#慎用全局变量" class="headerlink" title="慎用全局变量"></a>慎用全局变量</h3><ul>
<li>全局变量定义在全局执行上下文，是所有作用域链的顶端</li>
<li>全局执行上下文一直存在于上下文执行栈，直到程序退出</li>
<li>如果某个局部作用域出现了同名变量则会遮蔽或污染全局</li>
</ul>
<p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E4%BC%98%E5%8C%96%E6%85%8E%E7%94%A8%E5%85%A8%E5%B1%80%E5%8F%98%E9%87%8F.png" alt="优化慎用全局变量"></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 全局变量</span></span><br><span class="line"><span class="keyword">var</span> i,</span><br><span class="line">  str = <span class="string">&#x27;&#x27;</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">packageDom1</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">1000</span>; i++) &#123;</span><br><span class="line">    str += i</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">packageDom1()</span><br><span class="line"></span><br><span class="line"><span class="comment">// 局部变量</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">packageDom2</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">let</span> str = <span class="string">&#x27;&#x27;</span></span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">1000</span>; i++) &#123;</span><br><span class="line">    str += i</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">packageDom2()</span><br></pre></td></tr></table></figure>

<h3 id="缓存数据"><a href="#缓存数据" class="headerlink" title="缓存数据"></a>缓存数据</h3><ul>
<li>减少声明和语句数（词法、语法）</li>
<li>缓存数据（作用域链查找变快）</li>
</ul>
<p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E4%BC%98%E5%8C%96%E7%BC%93%E5%AD%98%E6%95%B0%E6%8D%AE.png" alt="优化缓存数据"></p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;skip&quot;</span> <span class="attr">class</span>=<span class="string">&quot;skip&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="javascript"><span class="comment">// 缓存数据：对于需要多次使用的数据进行提前保存，后续进行使用</span></span></span><br><span class="line"><span class="javascript"><span class="keyword">var</span> oBox = <span class="built_in">document</span>.getElementById(<span class="string">&#x27;skip&#x27;</span>)</span></span><br><span class="line"></span><br><span class="line"><span class="javascript"><span class="function"><span class="keyword">function</span> <span class="title">hasClassName1</span>(<span class="params">ele, cls</span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">  <span class="built_in">console</span>.log(ele.className)</span></span><br><span class="line"><span class="javascript">  <span class="keyword">return</span> ele.className === cls</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="javascript">hasClassName1(oBox, <span class="string">&#x27;skip&#x27;</span>)</span></span><br><span class="line"></span><br><span class="line"><span class="javascript"><span class="function"><span class="keyword">function</span> <span class="title">hasClassName2</span>(<span class="params">ele, cls</span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">  <span class="keyword">var</span> clsName = ele.className</span></span><br><span class="line"><span class="javascript">  <span class="built_in">console</span>.log(clsName)</span></span><br><span class="line"><span class="javascript">  <span class="keyword">return</span> clsName === cls</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="javascript">hasClassName2(oBox, <span class="string">&#x27;skip&#x27;</span>)</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h3 id="减少访问层级"><a href="#减少访问层级" class="headerlink" title="减少访问层级"></a>减少访问层级</h3><p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E4%BC%98%E5%8C%96%E5%87%8F%E5%B0%91%E8%AE%BF%E9%97%AE%E5%B1%82%E7%BA%A7.png" alt="优化减少访问层级"></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person1</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="built_in">this</span>.name = <span class="string">&#x27;bird&#x27;</span></span><br><span class="line">  <span class="built_in">this</span>.age = <span class="number">14</span></span><br><span class="line">  <span class="built_in">this</span>.getAge = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">this</span>.age</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> p1 = <span class="keyword">new</span> Person1()</span><br><span class="line"><span class="built_in">console</span>.log(p1.getAge())</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person2</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="built_in">this</span>.name = <span class="string">&#x27;bird&#x27;</span></span><br><span class="line">  <span class="built_in">this</span>.age = <span class="number">14</span></span><br><span class="line">  <span class="built_in">this</span>.getAge = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">this</span>.age</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> p2 = <span class="keyword">new</span> Person2()</span><br><span class="line"><span class="built_in">console</span>.log(p2.age)</span><br></pre></td></tr></table></figure>

<h3 id="字面量与构造式"><a href="#字面量与构造式" class="headerlink" title="字面量与构造式"></a>字面量与构造式</h3><p>直接通过字面量来创建的执行速度远比 new 关键字创建的速度快</p>
<ul>
<li>因为 new 相当于调用一个函数</li>
<li>字面量是直接开辟一个空间往里存</li>
</ul>
<p>引用数据类型，字面量与构造式方式没有太大区别。基本数据类型，字面量与构造式方式差别就很大了</p>
<p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E4%BC%98%E5%8C%96%E5%AD%97%E9%9D%A2%E9%87%8F%E4%B8%8E%E6%9E%84%E9%80%A0%E5%BC%8F.png" alt="优化字面量与构造式"></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> test = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">var</span> obj = <span class="keyword">new</span> <span class="built_in">Object</span>()</span><br><span class="line">  obj.name = <span class="string">&#x27;zce&#x27;</span></span><br><span class="line">  obj.age = <span class="number">38</span></span><br><span class="line">  obj.slogan = <span class="string">&#x27;声明一个 obj&#x27;</span></span><br><span class="line">  <span class="keyword">return</span> obj</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> test = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">var</span> obj = &#123;</span><br><span class="line">    name: <span class="string">&#x27;zce&#x27;</span>,</span><br><span class="line">    age: <span class="number">38</span>,</span><br><span class="line">    slogan: <span class="string">&#x27;声明一个 obj&#x27;</span>,</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> obj</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(test())</span><br></pre></td></tr></table></figure>

<h3 id="减少循环体活动"><a href="#减少循环体活动" class="headerlink" title="减少循环体活动"></a>减少循环体活动</h3><ul>
<li>把循环体里边重复的事情，如果说值不变，没必要每次都重新获取一遍</li>
<li>采用另一种从后往前遍历思路，可以少做一些条件判断</li>
</ul>
<p><img data-src="https://gitee.com/lilyn/pic/raw/master/lagoulearn-img/%E4%BC%98%E5%8C%96%E5%87%8F%E5%B0%91%E5%BE%AA%E7%8E%AF%E4%BD%93%E6%B4%BB%E5%8A%A8.png" alt="优化减少循环体活动"></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> test = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">var</span> i</span><br><span class="line">  <span class="keyword">var</span> arr = [<span class="string">&#x27;bird&#x27;</span>, <span class="number">18</span>, <span class="string">&#x27;bird can fly&#x27;</span>]</span><br><span class="line">  <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; arr.length; i++) &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(i)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 对不经常发生改变的数据进行缓存</span></span><br><span class="line"><span class="keyword">var</span> test = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">var</span> i</span><br><span class="line">  <span class="keyword">var</span> arr = [<span class="string">&#x27;bird&#x27;</span>, <span class="number">18</span>, <span class="string">&#x27;bird can fly&#x27;</span>]</span><br><span class="line">  <span class="keyword">var</span> len = arr.length</span><br><span class="line">  <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; len; i++) &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(i)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用 while 循环</span></span><br><span class="line"><span class="keyword">var</span> test = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">var</span> arr = [<span class="string">&#x27;bird&#x27;</span>, <span class="number">18</span>, <span class="string">&#x27;bird can fly&#x27;</span>]</span><br><span class="line">  <span class="keyword">var</span> i = arr.length</span><br><span class="line">  <span class="keyword">while</span> (i--) &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(i)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">test()</span><br></pre></td></tr></table></figure>

<h3 id="防抖和节流"><a href="#防抖和节流" class="headerlink" title="防抖和节流"></a>防抖和节流</h3><p>在一些高频率事件触发的场景下，我们不希望对应的事件函数多次执行</p>
<ul>
<li>场景：滚动事件、输入的模糊匹配、轮播图切换、点击操作</li>
<li>浏览器默认都会有自己的监听事件间隔（4~6ms），如果检测到多次事件的监听执行，那么就会造成不必要的资源浪费</li>
</ul>
<p>防抖：对于高频操作，我们只希望识别一次点击，可以人为是第一次或者最后一次</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">id</span>=<span class="string">&quot;btn&quot;</span>&gt;</span>点击<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="javascript">  <span class="keyword">var</span> btn = <span class="built_in">document</span>.getElementById(<span class="string">&#x27;btn&#x27;</span>)</span></span><br><span class="line"><span class="javascript">  <span class="function"><span class="keyword">function</span> <span class="title">btnClick</span>(<span class="params">ev</span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">    <span class="built_in">console</span>.log(<span class="string">&#x27;点击了&#x27;</span>, <span class="built_in">this</span>, ev)</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  /**</span><br><span class="line">   * handle 最终需要执行的事件监听</span><br><span class="line">   * wait 事件触发之后多久开始执行</span><br><span class="line">   * immediate 控制执行第一次还是最后一次</span><br><span class="line">   */</span><br><span class="line"><span class="javascript">  <span class="function"><span class="keyword">function</span> <span class="title">myDebounce</span>(<span class="params">handle, wait, immediate</span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">    <span class="comment">// 参数类型判断及默认值处理</span></span></span><br><span class="line"><span class="javascript">    <span class="keyword">if</span> (<span class="keyword">typeof</span> handle !== <span class="string">&#x27;function&#x27;</span>) <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">&#x27;handle must be a function&#x27;</span>)</span></span><br><span class="line"><span class="javascript">    <span class="keyword">if</span> (<span class="keyword">typeof</span> wait === <span class="string">&#x27;undefined&#x27;</span>) wait = <span class="number">300</span></span></span><br><span class="line"><span class="javascript">    <span class="keyword">if</span> (<span class="keyword">typeof</span> wait === <span class="string">&#x27;boolean&#x27;</span>) &#123;</span></span><br><span class="line">      immediate = wait</span><br><span class="line">      wait = 300</span><br><span class="line">    &#125;</span><br><span class="line"><span class="javascript">    <span class="keyword">if</span> (<span class="keyword">typeof</span> immediate !== <span class="string">&#x27;boolean&#x27;</span>) immediate = <span class="literal">false</span></span></span><br><span class="line"></span><br><span class="line"><span class="javascript">    <span class="comment">// 如果我们想要执行最后一次，那么就意味着无论我们点击了多少次，前面N-1次都无用</span></span></span><br><span class="line"><span class="javascript">    <span class="keyword">let</span> timer = <span class="literal">null</span></span></span><br><span class="line"><span class="javascript">    <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> <span class="title">proxy</span>(<span class="params">...args</span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">      <span class="comment">// 如果要向实现第一次执行，那么可以添加 timer 为 null 的判断</span></span></span><br><span class="line"><span class="javascript">      <span class="keyword">let</span> init = immediate &amp;&amp; !timer</span></span><br><span class="line"><span class="javascript">      <span class="built_in">clearTimeout</span>(timer)</span></span><br><span class="line"><span class="javascript">      timer = <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span></span><br><span class="line"><span class="javascript">        timer = <span class="literal">null</span></span></span><br><span class="line"><span class="javascript">        !immediate ? handle.apply(<span class="built_in">this</span>, args) : <span class="literal">null</span></span></span><br><span class="line">      &#125;, wait)</span><br><span class="line"><span class="javascript">      <span class="comment">// 如果当前传递进行的是 true（立即执行）</span></span></span><br><span class="line"><span class="javascript">      init ? handle.apply(<span class="built_in">this</span>, args) : <span class="literal">null</span></span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"><span class="javascript">  <span class="comment">// 当我们执行了按钮点击就会执行...返回的proxy</span></span></span><br><span class="line"><span class="javascript">  btn.onclick = myDebounce(btnClick, <span class="number">1000</span>, <span class="literal">true</span>)</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>节流：对于高频操作，我们可以自己设置频率，让本来会执行很多次的事件触发，按我们定义的频率减少触发的次数</p>
<ol>
<li>假设当前在 5ms 时间点上执行一次 proxy，我们就可以用这个时间减去上次执行的时间，此时就会有一个时间差</li>
<li>前置条件：我们自己定义了一个 wait，比如定义的是 500ms</li>
<li><code>wait - (now - previous)</code></li>
<li>此时如果上如结果是大于 0，就意味着当次的操作是一个高频触发，我们想法让它不要去执行 handle，如果这个结果小于等于 0，就意味着当次不是一个高频操作，那么我们就可以执行 handle</li>
<li>此时我们就可以在 500ms 内想办法让所有的高频操作在将来都有一次执行就可以，不需要给每个高频操作添加一个定时器</li>
</ol>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">style</span>&gt;</span></span><br><span class="line">  body &#123;</span><br><span class="line">    height: 5000px;</span><br><span class="line">  &#125;</span><br><span class="line"><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="javascript">  <span class="function"><span class="keyword">function</span> <span class="title">scrollFn</span>(<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">    <span class="built_in">console</span>.log(<span class="string">&#x27;滚动了&#x27;</span>)</span></span><br><span class="line">  &#125;</span><br><span class="line"><span class="javascript">  <span class="function"><span class="keyword">function</span> <span class="title">myThrottle</span>(<span class="params">handle, wait</span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">    <span class="keyword">if</span> (<span class="keyword">typeof</span> handle !== <span class="string">&#x27;function&#x27;</span>) <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">&#x27;handle must be a function&#x27;</span>)</span></span><br><span class="line"><span class="javascript">    <span class="keyword">if</span> (<span class="keyword">typeof</span> wait === <span class="string">&#x27;undefined&#x27;</span>) wait = <span class="number">300</span></span></span><br><span class="line"></span><br><span class="line"><span class="javascript">    <span class="keyword">let</span> previous = <span class="number">0</span> <span class="comment">// 上一次执行的时间</span></span></span><br><span class="line"><span class="javascript">    <span class="keyword">let</span> timer = <span class="literal">null</span> <span class="comment">// 用它来管理定时器</span></span></span><br><span class="line"><span class="javascript">    <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> <span class="title">proxy</span>(<span class="params">...args</span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">      <span class="comment">// 此时说明是一个非高频操作，可以执行 handle</span></span></span><br><span class="line"><span class="javascript">      <span class="keyword">let</span> now = <span class="keyword">new</span> <span class="built_in">Date</span>() <span class="comment">// 当前执行的时刻时间点</span></span></span><br><span class="line"><span class="javascript">      <span class="keyword">let</span> interval = wait - (now - previous)</span></span><br><span class="line"><span class="javascript">      <span class="keyword">if</span> (interval &lt;= <span class="number">0</span>) &#123;</span></span><br><span class="line"><span class="javascript">        <span class="built_in">clearTimeout</span>(timer)</span></span><br><span class="line"><span class="javascript">        timer = <span class="literal">null</span></span></span><br><span class="line"><span class="javascript">        handle.apply(<span class="built_in">this</span>, args)</span></span><br><span class="line"><span class="javascript">        previous = +<span class="keyword">new</span> <span class="built_in">Date</span>()</span></span><br><span class="line">      &#125;</span><br><span class="line"><span class="javascript">      <span class="comment">// 当我们发现当前系统有一个定时器，就意味着我们不需要再开启定时器</span></span></span><br><span class="line"><span class="javascript">      <span class="keyword">if</span> (!timer) &#123;</span></span><br><span class="line"><span class="javascript">        <span class="comment">// 此时说明这次操作发生在我们定义的频次时间范围内，那就不执行 handle</span></span></span><br><span class="line"><span class="javascript">        <span class="comment">// 这时候我们可以定义一个定时器，让 handle 在 interval 之后去执行</span></span></span><br><span class="line"><span class="javascript">        timer = <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span></span><br><span class="line"><span class="javascript">          <span class="built_in">clearTimeout</span>(timer) <span class="comment">// 这个操作只是将系统中的定时器清除了，但是 timer 中的值还在</span></span></span><br><span class="line"><span class="javascript">          timer = <span class="literal">null</span></span></span><br><span class="line"><span class="javascript">          handle.apply(<span class="built_in">this</span>, args)</span></span><br><span class="line"><span class="javascript">          previous = +<span class="keyword">new</span> <span class="built_in">Date</span>()</span></span><br><span class="line">        &#125;, interval)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"><span class="javascript">  <span class="built_in">window</span>.onscroll = myThrottle(scrollFn, <span class="number">1000</span>)</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>


    </div>

    
    
    

	<div>
		  
			
<div class="my_post_copyright clearfix">
  <script src="//cdn.bootcss.com/clipboard.js/1.5.10/clipboard.min.js"></script>
  
  <!-- JS库 sweetalert 可修改路径 -->
  <script src="https://cdn.bootcss.com/jquery/2.0.0/jquery.min.js"></script>
  <script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
  <article class="box-left">
    <img src="https://gitee.com/lilyn/pic/raw/master/logo.jpg">
  </article>
  <article class="box-right">
    <p><span>本文标题:</span><a href="/posts/3344fd09/">JS 垃圾回收与性能优化</a></p>
    <p><span>文章作者:</span><a href="/" title="访问 LiLyn 的个人博客">LiLyn</a></p>
    <p><span>原始链接:</span><a href="/posts/3344fd09/" title="JS 垃圾回收与性能优化">http://llmysnow.top/posts/3344fd09/</a>
    <span class="copy-path"  title="点击复制文章链接"><i class="fa fa-clipboard" data-clipboard-text="http://llmysnow.top/posts/3344fd09/"  aria-label="复制成功！"></i></span>
  </p>
    <p><span>许可协议:</span>转载请保留原文链接及作者。</p>  
  </article>
</div>
<script> 
    var clipboard = new Clipboard('.fa-clipboard');
    $(".fa-clipboard").click(function(){
      clipboard.on('success', function(){
        swal({   
          title: "",   
          text: '复制成功',
          icon: "success", 
          showConfirmButton: true
          });
    });
    });  
</script>

		  
	</div>

      <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/JavaScript/" rel="tag"><i class="fa fa-tag"></i> JavaScript</a>
              <a href="/tags/%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6/" rel="tag"><i class="fa fa-tag"></i> 垃圾回收</a>
              <a href="/tags/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/" rel="tag"><i class="fa fa-tag"></i> 性能优化</a>
              <a href="/tags/Performance/" rel="tag"><i class="fa fa-tag"></i> Performance</a>
              <a href="/tags/%E4%BB%A3%E7%A0%81%E4%BC%98%E5%8C%96/" rel="tag"><i class="fa fa-tag"></i> 代码优化</a>
          </div>
		 
		<!--post-tags 彩色标签-->
		<script type="text/javascript">
		var tagsall=document.getElementsByClassName("post-tags")
		for (var i = tagsall.length - 1; i >= 0; i--){
			var tags=tagsall[i].getElementsByTagName("a");
			for (var j = tags.length - 1; j >= 0; j--) {
				var r=Math.floor(Math.random()*75+130);
				var g=Math.floor(Math.random()*75+100);
				var b=Math.floor(Math.random()*75+80);
				tags[j].style.background = "rgb("+r+","+g+","+b+")";
				tags[j].style.color = "#fff";
				tags[j].style.padding = "0 10px";
			}
		}                        
		</script>

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/posts/6669e648/" rel="prev" title="圣杯布局和双飞翼布局">
      <i class="fa fa-chevron-left"></i> 圣杯布局和双飞翼布局
    </a></div>
      <div class="post-nav-item">
    <a href="/posts/ea5004b1/" rel="next" title="JS this指向问题">
      JS this指向问题 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#JavaScript-%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86"><span class="nav-text">JavaScript 内存管理</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E4%B8%8E%E5%B8%B8%E8%A7%81-GC-%E7%AE%97%E6%B3%95"><span class="nav-text">垃圾回收与常见 GC 算法</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#JavaScript-%E4%B8%AD%E7%9A%84%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6"><span class="nav-text">JavaScript 中的垃圾回收</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#GC-%E7%AE%97%E6%B3%95"><span class="nav-text">GC 算法</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E5%BC%95%E7%94%A8%E8%AE%A1%E6%95%B0"><span class="nav-text">引用计数</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E6%A0%87%E8%AE%B0%E6%B8%85%E9%99%A4"><span class="nav-text">标记清除</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E6%A0%87%E8%AE%B0%E6%95%B4%E7%90%86"><span class="nav-text">标记整理</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#V8-%E5%BC%95%E6%93%8E%E7%9A%84%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6"><span class="nav-text">V8 引擎的垃圾回收</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#V8-%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E7%AD%96%E7%95%A5"><span class="nav-text">V8 垃圾回收策略</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#V8-%E5%9B%9E%E6%94%B6%E6%96%B0%E8%80%81%E7%94%9F%E4%BB%A3%E5%AF%B9%E8%B1%A1"><span class="nav-text">V8 回收新老生代对象</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Performance-%E5%B7%A5%E5%85%B7"><span class="nav-text">Performance 工具</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BB%BB%E5%8A%A1%E7%AE%A1%E7%90%86%E5%99%A8%E7%9B%91%E6%8E%A7%E5%86%85%E5%AD%98"><span class="nav-text">任务管理器监控内存</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Timeline-%E8%AE%B0%E5%BD%95%E5%86%85%E5%AD%98"><span class="nav-text">Timeline 记录内存</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%A0%86%E5%BF%AB%E7%85%A7%E6%9F%A5%E8%AF%A2%E5%88%86%E7%A6%BB-DOM"><span class="nav-text">堆快照查询分离 DOM</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#V8-%E5%BC%95%E6%93%8E%E5%B7%A5%E4%BD%9C%E6%B5%81%E7%A8%8B"><span class="nav-text">V8 引擎工作流程</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%A0%86%E6%A0%88%E5%86%85%E5%AD%98%E5%A4%84%E7%90%86"><span class="nav-text">堆栈内存处理</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%9F%BA%E6%9C%AC%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B"><span class="nav-text">基本数据类型</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%BC%95%E7%94%A8%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B"><span class="nav-text">引用数据类型</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%87%BD%E6%95%B0%E5%A0%86%E6%A0%88%E5%A4%84%E7%90%86"><span class="nav-text">函数堆栈处理</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E9%97%AD%E5%8C%85%E5%A0%86%E6%A0%88%E5%A4%84%E7%90%86"><span class="nav-text">闭包堆栈处理</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%BB%A3%E7%A0%81%E4%BC%98%E5%8C%96"><span class="nav-text">代码优化</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E9%97%AD%E5%8C%85%E4%B8%8E%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6"><span class="nav-text">闭包与垃圾回收</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%BE%AA%E7%8E%AF%E6%B7%BB%E5%8A%A0%E4%BA%8B%E4%BB%B6"><span class="nav-text">循环添加事件</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BA%8B%E4%BB%B6%E5%A7%94%E6%89%98"><span class="nav-text">事件委托</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#JSBench"><span class="nav-text">JSBench</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%87%8F%E5%B0%91%E5%88%A4%E6%96%AD%E5%B1%82%E7%BA%A7"><span class="nav-text">减少判断层级</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%85%8E%E7%94%A8%E5%85%A8%E5%B1%80%E5%8F%98%E9%87%8F"><span class="nav-text">慎用全局变量</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BC%93%E5%AD%98%E6%95%B0%E6%8D%AE"><span class="nav-text">缓存数据</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%87%8F%E5%B0%91%E8%AE%BF%E9%97%AE%E5%B1%82%E7%BA%A7"><span class="nav-text">减少访问层级</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%AD%97%E9%9D%A2%E9%87%8F%E4%B8%8E%E6%9E%84%E9%80%A0%E5%BC%8F"><span class="nav-text">字面量与构造式</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%87%8F%E5%B0%91%E5%BE%AA%E7%8E%AF%E4%BD%93%E6%B4%BB%E5%8A%A8"><span class="nav-text">减少循环体活动</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E9%98%B2%E6%8A%96%E5%92%8C%E8%8A%82%E6%B5%81"><span class="nav-text">防抖和节流</span></a></li></ol></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="LiLyn"
      src="/images/logo.jpg">
  <p class="site-author-name" itemprop="name">LiLyn</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">70</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">10</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">162</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/llwodexue" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;llwodexue" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://blog.csdn.net/qq_38689395" title="CSDN → https:&#x2F;&#x2F;blog.csdn.net&#x2F;qq_38689395" rel="noopener" target="_blank"><i class="fas fa-copyright fa-fw"></i>CSDN</a>
      </span>
  </div>


  <div class="links-of-blogroll motion-element">
    <div class="links-of-blogroll-title"><i class="fa fa-link fa-fw"></i>
      友情链接
    </div>
    <ul class="links-of-blogroll-list">
        <li class="links-of-blogroll-item">
          <a href="https://scx69.gitee.io/blogs/" title="https:&#x2F;&#x2F;scx69.gitee.io&#x2F;blogs&#x2F;" rel="noopener" target="_blank">花开满城</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="http://yixin-oss.gitee.io/daytoy/" title="http:&#x2F;&#x2F;yixin-oss.gitee.io&#x2F;daytoy&#x2F;" rel="noopener" target="_blank">daytoy</a>
        </li>
    </ul>
  </div>

      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2022</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">LiLyn</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-area"></i>
    </span>
    <span title="站点总字数">463k</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
    <span title="站点阅读时长">7:01</span>
</div>

<!--
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Gemini</a> 强力驱动
  </div>-->

<!--
<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
<div class="powered-by">
  <i class="fa fa-user-md"></i>
  <span id="busuanzi_container_site_pv">
    本站访问量:<span id="busuanzi_value_site_pv"></span>次
  </span>
  <span class="post-meta-divider">|</span>
  <span id="busuanzi_container_site_uv">
    本站总访客量：<span id="busuanzi_value_site_uv"></span>人
  </span>
</div>-->

        








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="//cdn.jsdelivr.net/npm/lozad@1/dist/lozad.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>




  
  <script>
    (function(){
      var canonicalURL, curProtocol;
      //Get the <link> tag
      var x=document.getElementsByTagName("link");
		//Find the last canonical URL
		if(x.length > 0){
			for (i=0;i<x.length;i++){
				if(x[i].rel.toLowerCase() == 'canonical' && x[i].href){
					canonicalURL=x[i].href;
				}
			}
		}
    //Get protocol
	    if (!canonicalURL){
	    	curProtocol = window.location.protocol.split(':')[0];
	    }
	    else{
	    	curProtocol = canonicalURL.split(':')[0];
	    }
      //Get current URL if the canonical URL does not exist
	    if (!canonicalURL) canonicalURL = window.location.href;
	    //Assign script content. Replace current URL with the canonical URL
      !function(){var e=/([http|https]:\/\/[a-zA-Z0-9\_\.]+\.baidu\.com)/gi,r=canonicalURL,t=document.referrer;if(!e.test(r)){var n=(String(curProtocol).toLowerCase() === 'https')?"https://sp0.baidu.com/9_Q4simg2RQJ8t7jm9iCKT-xh_/s.gif":"//api.share.baidu.com/s.gif";t?(n+="?r="+encodeURIComponent(document.referrer),r&&(n+="&l="+r)):r&&(n+="?l="+r);var i=new Image;i.src=n}}(window);})();
  </script>




  
<script src="/js/local-search.js"></script>













  

  

  <!-- 动态线条背景 -->
  <script type="text/javascript" src="//cdn.bootcss.com/canvas-nest.js/1.0.0/canvas-nest.min.js"></script>
  <!-- 页面点击小红心 -->
  <script type="text/javascript">
	!function(e,t,a){function n(){c(".heart{width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);}.heart:after,.heart:before{content: '';width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: fixed;}.heart:after{top: -5px;}.heart:before{left: -5px;}"),o(),r()}function r(){for(var e=0;e<d.length;e++)d[e].alpha<=0?(t.body.removeChild(d[e].el),d.splice(e,1)):(d[e].y--,d[e].scale+=.004,d[e].alpha-=.013,d[e].el.style.cssText="left:"+d[e].x+"px;top:"+d[e].y+"px;opacity:"+d[e].alpha+";transform:scale("+d[e].scale+","+d[e].scale+") rotate(45deg);background:"+d[e].color+";z-index:99999");requestAnimationFrame(r)}function o(){var t="function"==typeof e.onclick&&e.onclick;e.onclick=function(e){t&&t(),i(e)}}function i(e){var a=t.createElement("div");a.className="heart",d.push({el:a,x:e.clientX-5,y:e.clientY-5,scale:1,alpha:1,color:s()}),t.body.appendChild(a)}function c(e){var a=t.createElement("style");a.type="text/css";try{a.appendChild(t.createTextNode(e))}catch(t){a.styleSheet.cssText=e}t.getElementsByTagName("head")[0].appendChild(a)}function s(){return"rgb("+~~(255*Math.random())+","+~~(255*Math.random())+","+~~(255*Math.random())+")"}var d=[];e.requestAnimationFrame=function(){return e.requestAnimationFrame||e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame||e.oRequestAnimationFrame||e.msRequestAnimationFrame||function(e){setTimeout(e,1e3/60)}}(),n()}(window,document);
  </script>
<script src="/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"pluginRootPath":"live2dw/","pluginJsPath":"lib/","pluginModelPath":"assets/","tagMode":false,"log":false,"model":{"jsonPath":"/live2dw/assets/hijiki.model.json"},"display":{"position":"right","width":150,"height":300},"mobile":{"show":true},"react":{"opacity":0.7}});</script></body>
</html>